﻿using System.Linq.Expressions;
using System.Reflection;

namespace System
{
	public static class ReflectionExtensions
	{
		public static TDelegate Compile<TDelegate>(this Expression<TDelegate> expression)
		{
			var compiledDelegate = CompilePropertyGetterExpression(expression, typeof(TDelegate));
			return (TDelegate)compiledDelegate;
		}

		static object CompilePropertyGetterExpression(LambdaExpression expression, Type delegateType)
		{
			var member = GetPropertyFromExpression(expression);

			if (member == null)
			{
				throw new NotSupportedException("FluentValidation for WP7 can only be used with expressions that reference public properties, eg x => x.SomeProperty");
			}

			var compiledDelegate = Delegate.CreateDelegate(delegateType, member.GetGetMethod());
			return compiledDelegate;
		}

		static PropertyInfo GetPropertyFromExpression(LambdaExpression expression)
		{
			var memberExp = UnwrapUnary(expression.Body);

			if (memberExp == null)
			{
				return null;
			}

			return memberExp.Member as PropertyInfo;
		}

		private static MemberExpression UnwrapUnary(Expression toUnwrap)
		{
			if (toUnwrap is UnaryExpression)
			{
				return ((UnaryExpression)toUnwrap).Operand as MemberExpression;
			}

			return toUnwrap as MemberExpression;
		}
	}
}
